#ifndef _CPU
#define _CPU
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <ctime>
#ifndef _STORE_HPP
#define _STORE_HPP

template <class T, int length = 5>
struct Cycle_Queue
{
    int front = 0, rear = 0;
    T node[length + 1];
    bool busy[length + 1];

    Cycle_Queue(){memset(busy, 0, sizeof(busy));}

    void clear()
    {
        front = rear = 0;
        memset(busy, 0, sizeof(busy));
    }

    int get_next(int now) 
    {
        return (now + 1) >= (length + 1) ? 0 : now + 1;
    }

    int get_pre(int now)
    {
        return (now - 1) < 0 ? length : now - 1;
    }
    
    bool empty()
    {
        return front == rear;
    }

    bool full()
    {
        return get_next(rear) == front;
    }

    int push(T newnode)
    {
        if (full())
        {
            puts("queue push error : full");
            exit(0);
        }

        node[rear = get_next(rear)] = newnode;
        node[rear].pos = rear;
        busy[rear] = 1;
        return rear;
    }

    void pop()
    {
        if (empty())
        {
            puts("queue pop error : empty");
            exit(0);
        }

        front = get_next(front);
        busy[front] = 0;
    }

    void pop_rear()
    {
        if (empty())
        {
            puts("queue pop_rear error : empty");
            exit(0);
        }

        busy[rear] = 0;
        rear = get_pre(rear);
    }

    T& get_rear()
    {
        if (empty())
        {
            puts("queue get_rear error : empty");
            exit(0);
        }

        return node[rear];
    }

    T& get_front()
    {
        if (empty())
        {
            puts("queue get_front error : empty");
            exit(0);
        }

        return node[get_next(front)];
    }

    T& get_sec()
    {
        if (empty() || get_next(front) == rear)
        {
            puts("queue get_sec error : size < 2");
            exit(0);
        }
        return node[get_next(get_next(front))];
    }

    int next_pos()
    {
        return get_next(rear);
    }
};

template <class T, int length = 5>
struct Array
{
    T node[length];
    bool busy[length];
    int size = 0;

    Array(){memset(busy, 0, sizeof(busy));}

    void clear()
    {
        size = 0;
        memset(busy, 0, sizeof(busy));
    }
    
    bool empty()
    {
        return size == 0;
    }

    bool full()
    {
        return size == length;
    }

    int push(T newnode)
    {
        if (full())
        {
            puts("array push error : full");
            exit(0);
        }

        for (int i = 0; i < length; i++)
            if (!busy[i])
            {
                busy[i] = 1;
                node[i] = newnode;
                size++;
                return i;
            }
            
        return 0;
    }

    void pop(int pos)
    {
        if (empty())
        {
            puts("array pop error : empty");
            exit(0);
        }
        
        busy[pos] = 0;
        size--;
    }
};

#endif


#ifndef _arithmetic_hpp
#define _arithmetic_hpp

using uint = unsigned int;

uint hex_to_dec(char ch)
{
    if (ch == 'A') return 10;
    if (ch == 'B') return 11;
    if (ch == 'C') return 12;
    if (ch == 'D') return 13;
    if (ch == 'E') return 14;
    if (ch == 'F') return 15;
    return ch - '0';
}

uint sext(uint x, int len)
{
    if (x & (1 << len))
        x += ~((1 << (len + 1)) - 1);
    return x;
}

#endif
// #define debug2
// #define func

class CPU
{
    using uint = unsigned int;
    static const int queue_len = 5;
    friend struct Reorder_Buffer;
    friend struct Reservation_Station;
    friend struct Load_Store_Buffer;
private:

    uint pc_prev = 0, pc_new = 0;

    struct instruction
    {
        uint rv32i, pc;
        bool isissue = 1;

        instruction(uint _rv32i = 0, uint _pc = 0, bool _isissue = 1) 
            : rv32i(_rv32i), pc(_pc), isissue(_isissue) {}
    } ins;

    struct Memory
    {
        unsigned char mem[500010];
    } M;

    struct Registers
    {
        uint reg[32];
        int reg_state[32];

        Registers() {memset(reg_state, -1, sizeof(reg_state));}

    } R_new, R_prev;

    struct Reorder_Buffer
    {
        struct node
        {
            int opcode, func3, func7, dest = -1, pc = -1, pos = 0;
            uint val = 0;
            bool ready = 0, isjump = 0, iscommit = 0, end = 0;

            node(int _opcode = -1, int _func3 = -1, int _func7 = -1) 
                : opcode(_opcode), func3(_func3), func7(_func7) {}

            void print() const
            {
                puts("ROB node:");
                printf("opcode:%d func3:%d func7:%d dest:%d pc:%d\n", opcode, func3, func7, dest, pc);
                printf("val:%u ready:%d isjump:%d iscommit:%d end:%d\n", val, ready, isjump, iscommit, end);
                puts("");
            }
        };

        Cycle_Queue<node, CPU::queue_len> h;

    } ROB_new, ROB_prev;

    struct Reservation_Station
    {
        struct node
        {
            int opcode, func3, func7; 
            uint Vj = 0, Vk = 0, A = 0; int Qj = -1, Qk = -1, dest = -1, pc = 0;

            node(int _opcode = -1, int _func3 = -1, int _func7 = -1) 
                : opcode(_opcode), func3(_func3), func7(_func7) {}

            void print() const
            {
                puts("ROB node:");
                printf("opcode:%d func3:%d func7:%d dest:%d pc:%d\n", opcode, func3, func7, dest, pc);
                printf("Vj:%u Vk:%u A:%u Qj:%d Qk:%d\n", Vj, Vk, A, Qj, Qk);
                puts("");
            }
        };

        Array<node, CPU::queue_len> h;

    } RS_new, RS_prev;

    struct Load_Store_Buffer
    {
        struct node
        {
            int opcode, func3, func7; 
            uint Vj = 0, Vk = 0, A = 0; int Qj = -1, Qk = -1, tim = -1, dest = -1, pos = 0;
            bool iscommit = 0;

            node(int _opcode = -1, int _func3 = -1, int _func7 = -1) 
                : opcode(_opcode), func3(_func3), func7(_func7) {}

            void print() const
            {
                puts("ROB node:");
                printf("opcode:%d func3:%d func7:%d\n", opcode, func3, func7);
                printf("Vj:%u Vk:%u A:%u Qj:%d Qk:%d tim:%d iscommit:%d\n", Vj, Vk, A, Qj, Qk, tim, iscommit);
                puts("");
            }
        };

        Cycle_Queue<node, CPU::queue_len> h;

    } LSB_new, LSB_prev;

    struct CDB
    {
        int dest; uint val; int pos; bool isjump = 0;
        CDB(int _dest = -1, uint _val = 0, int _pos = -1, bool _isjump = 0) 
            : dest(_dest), val(_val), pos(_pos), isjump(_isjump) {}

        void print() const
        {
            printf("dest:%d val:%u pos:%d isjump:%d\n", dest, val, pos, isjump);
        }
    };

    Reorder_Buffer::node issue_to_ROB, ROB_to_commit;
    Reservation_Station::node issue_to_RS, RS_to_ex;
    Load_Store_Buffer::node issue_to_LSB;

    CDB ex_to_CDB;
    CDB LSB_to_CDB_prev, LSB_to_CDB_new;
    CDB commit_to_reg;
    bool commit_to_LSB = 0;
    int commit_signal = 0; // 0 表示无    1 表示 pop   负数表示 pc

    std :: pair <int, int> issue_to_reg = std :: make_pair(-1, -1);

    // pc = -2 表示 Store Ready pc != -1 表示是 jump 操作

    void IQ_fetch();
    void IQ_issue();

    bool RS_ready(const CPU::Reservation_Station::node &t);
    int RS_find();
    void RS_run();
    void RS_ex();

    void ROB_run();
    void ROB_commit();

    void LSB_run();

    void reg_run();

    void update()
    {
        #ifdef func
            puts("");
            puts("---update---");
        #endif 
        R_prev = R_new; 
        pc_prev = pc_new;
        ROB_prev = ROB_new; 
        RS_prev = RS_new; 
        LSB_prev = LSB_new;

        issue_to_ROB = Reorder_Buffer::node();
        issue_to_RS = Reservation_Station::node();
        issue_to_LSB = Load_Store_Buffer::node();
        issue_to_reg = std::make_pair(-1, -1);

        LSB_to_CDB_prev = LSB_to_CDB_new;
        LSB_to_CDB_new = CDB();
        ex_to_CDB = CDB();

        commit_to_LSB = 0;
        commit_signal = 0;
        commit_to_reg = CDB();
        #ifdef func
            puts("");
            puts("------------");
        #endif 
    }

public:  

    void reader()
    {
        uint now = 0;
        char s[10];
        while (scanf("%s", s) != EOF)
        {
            if (s[0] == '@')
            {
                now = 0;
                for (int i = 1; i <= 8; i++)
                {
                    now = now << 4 | hex_to_dec(s[i]);
                }
            }
            else
            {
                M.mem[now++] = hex_to_dec(s[0]) << 4 | hex_to_dec(s[1]);
            }
        }
    }

    void runner()
    {
        srand(time(0));
        int p[5];
        for (int i = 0; i < 5; i++)
            p[i] = i;
        while (1)
        {
            std :: random_shuffle(p, p + 5);
            for (int i = 0; i < 5; i++)
            {
                if (p[i] == 0)
                {
                    ROB_run();
                    if (ROB_to_commit.end)
                    {
                        std::cout << std::dec << ((unsigned int)R_prev.reg[10] & 255u);
                        return;
                    }
                }
                else if (p[i] == 1)
                {
                    LSB_run();
                }
                else if (p[i] == 2)
                {
                    RS_run();
                }
                else if (p[i] == 3)
                {
                    IQ_fetch();
                }
                else 
                {
                    reg_run();
                }
            }

            update();
            
            RS_ex();
            IQ_issue();
            ROB_commit();
        }
    }
};


#ifndef _Instruction_Queue
#define _Instruction_Queue
#include <iostream>
#include <cstring>
#include <cstdio>




void CPU::IQ_fetch()
{
    #ifdef func
        puts("");
        puts("---IQ_fetch---");
    #endif 

    if (!ins.isissue && CPU::commit_signal >= 0)
        return;

    int tmp = CPU::pc_prev;
    if (CPU::commit_signal < 0)
        tmp = -CPU::commit_signal;

    #ifdef debug
        printf("[");
    #endif
    uint rv32i = 0;
    for (int i = 3; ~i; i--)
    {
        rv32i = rv32i << 8 | CPU::M.mem[tmp + i];
        #ifdef debug
            std::cout.fill('0');
            std::cout.width(2);
            std::cout << std::hex << (int)mem[pc + i] << ' ';
        #endif
    }

    if (rv32i == 0)
    {
        CPU::ins.isissue = 1;
        return;
    }

    #ifdef debug
        printf("]     ");
        std::cout << std::hex << pc << "       ";
        // printf("pc:%5d      ", pc);
    #endif

    CPU::ins = CPU::instruction(rv32i, tmp, 0);

    CPU::pc_new = tmp + 4;

    #ifdef func
        puts("--------------");
        puts("");
    #endif 
}

void CPU::IQ_issue()
{
    #ifdef func
        puts("");
        puts("---IQ_issue---");
    #endif 
    if (CPU::ins.isissue)
        return;

    uint rv32i = CPU::ins.rv32i, pc = CPU::ins.pc;
    bool isend = (rv32i == 0x0ff00513);

    uint opcode = rv32i & ((1 << 7) - 1);
    rv32i >>= 7;

    int rs1 = -1, rs2 = -1, rd = -1, func3 = 0, func7 = 0;
    uint imm = 0;
    if (opcode == 55) // LUI
    {
        rd = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;
        imm = rv32i << 12;
    }
    else if (opcode == 23) // AUIPC
    {   
        rd = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;
        imm = rv32i << 12;
    }
    else if (opcode == 111) // JAL
    {
        rd = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;
        imm |= (rv32i & ((1 << 8) - 1)) << 12;
        rv32i >>= 8;
        imm |= (rv32i & 1) << 11;
        rv32i >>= 1;
        imm |= (rv32i & ((1 << 10) - 1)) << 1;
        rv32i >>= 10;
        imm |= rv32i << 20;

        imm = sext(imm, 20);
    }
    else if (opcode == 103) // JALR
    {
        rd = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        func3 = rv32i & ((1 << 3) - 1);
        rv32i >>= 3;

        rs1 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        imm |= rv32i;
        
        imm = sext(imm, 11);
    }
    else if (opcode == 99) // BEQ ~ BGEU
    {
        imm |= (rv32i & 1) << 11;
        rv32i >>= 1;
        imm |= (rv32i & ((1 << 4) - 1)) << 1;
        rv32i >>= 4;

        func3 = rv32i & ((1 << 3) - 1);
        rv32i >>= 3;

        rs1 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        rs2 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        imm |= (rv32i & ((1 << 6) - 1)) << 5;
        rv32i >>= 6;

        imm |= (rv32i & 1) << 12;

        imm = sext(imm, 12);
    }
    else if (opcode == 3) // LB ~ LHU
    {
        rd = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        func3 = rv32i & ((1 << 3) - 1);
        rv32i >>= 3;

        rs1 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        imm |= rv32i;

        imm = sext(imm, 11);
    }
    else if (opcode == 35) // SB ~ SW
    {
        imm |= rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        func3 = rv32i & ((1 << 3) - 1);
        rv32i >>= 3;

        rs1 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        rs2 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        imm |= rv32i << 5;

        imm = sext(imm, 11);
    }
    else if (opcode == 19) // ADDI ~ SRAI
    {
        rd = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        func3 = rv32i & ((1 << 3) - 1);
        rv32i >>= 3;

        rs1 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        if (func3 == 1 || func3 == 5) // SLLI ~ SRAI
        {
            imm |= rv32i & ((1 << 5) - 1);
            rv32i >>= 5;

            func7 = rv32i;
        }
        else // ADDI ~ ANDI
        {
            imm |= rv32i;

            imm = sext(imm, 11);
        }
    }
    else if (opcode == 51) // ADD ~ AND
    {
        rd = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        func3 = rv32i & ((1 << 3) - 1);
        rv32i >>= 3;

        rs1 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        rs2 = rv32i & ((1 << 5) - 1);
        rv32i >>= 5;

        func7 = rv32i;
    }

    // L or S
    if (opcode == 3 || opcode == 35)
    {
        if (CPU::LSB_prev.h.full() || CPU::ROB_prev.h.full())
            return;
        else
            CPU::ins.isissue = 1;

        Reorder_Buffer::node ROBnode(opcode, func3, func7);
        ROBnode.dest = rd;
        ROBnode.ready = 0;
        ROBnode.end = isend;
        int b = CPU::ROB_prev.h.next_pos();

        Load_Store_Buffer::node LSBnode(opcode, func3, func7);
        if (opcode == 3)
        {
            if (~CPU::R_prev.reg_state[rs1])
            {
                int h = CPU::R_prev.reg_state[rs1];
                if (CPU::ROB_prev.h.node[h].ready)
                    LSBnode.Vj = CPU::ROB_prev.h.node[h].val;
                else
                    LSBnode.Qj = h;
            }
            else
                LSBnode.Vj = CPU::R_prev.reg[rs1];

            LSBnode.A = imm;
            LSBnode.dest = b;

            CPU::R_prev.reg_state[rd] = b;
        }
        else
        {
            if (~CPU::R_prev.reg_state[rs1])
            {
                int h = CPU::R_prev.reg_state[rs1];
                if (CPU::ROB_prev.h.node[h].ready)
                    LSBnode.Vj = CPU::ROB_prev.h.node[h].val;
                else
                    LSBnode.Qj = h;
            }
            else
                LSBnode.Vj = CPU::R_prev.reg[rs1];

            if (~CPU::R_prev.reg_state[rs2])
            {
                int h = CPU::R_prev.reg_state[rs2];
                if (CPU::ROB_prev.h.node[h].ready)
                    LSBnode.Vk = CPU::ROB_prev.h.node[h].val;
                else
                    LSBnode.Qk = h;
            }
            else
                LSBnode.Vk = CPU::R_prev.reg[rs2];

            LSBnode.A = imm;
            LSBnode.dest = b;
        }

        CPU::issue_to_ROB = ROBnode;
        CPU::issue_to_LSB = LSBnode;
    }
    else
    {
        if (CPU::RS_prev.h.full() || CPU::ROB_prev.h.full())
            return;
        else
            CPU::ins.isissue = 1;

        Reorder_Buffer::node ROBnode(opcode, func3, func7);
        ROBnode.dest = rd;
        ROBnode.ready = 0;
        ROBnode.end = isend;
        int b = CPU::ROB_prev.h.next_pos();

        Reservation_Station::node RSnode(opcode, func3, func7);
        if (~rs1)
        {
            if (~CPU::R_prev.reg_state[rs1])
            {
                int h = CPU::R_prev.reg_state[rs1];
                if (CPU::ROB_prev.h.node[h].ready)
                    RSnode.Vj = CPU::ROB_prev.h.node[h].val;
                else
                    RSnode.Qj = h;
            }
            else
                RSnode.Vj = CPU::R_prev.reg[rs1];
        }

        if (~rs2)
        {
            if (~CPU::R_prev.reg_state[rs2])
            {
                int h = CPU::R_prev.reg_state[rs2];
                if (CPU::ROB_prev.h.node[h].ready)
                    RSnode.Vk = CPU::ROB_prev.h.node[h].val;
                else
                    RSnode.Qk = h;
            }
            else
                RSnode.Vk = CPU::R_prev.reg[rs2];
        }

        RSnode.A = imm;
        RSnode.dest = b;
        RSnode.pc = pc;

        CPU::issue_to_reg = std::make_pair(rd, b);

        CPU::issue_to_ROB = ROBnode;
        CPU::issue_to_RS = RSnode;
    }

    #ifdef func
        puts("issue_to_ROB");
        CPU::issue_to_ROB.print();
        puts("issue_to_RS");
        CPU::issue_to_RS.print();
        puts("issue_to_LSB");
        CPU::issue_to_LSB.print();
        puts("--------------");
        puts("");
    #endif 
};

#endif
#ifndef _Reorder_Buffer
#define _Reorder_Buffer
#include <iostream>
#include <cstring>
#include <cstdio>




void CPU::ROB_run()
{
    #ifdef func
        puts("");
        puts("---ROB_run---");
    #endif 


    CPU::ROB_new = CPU::ROB_prev;

    if (CPU::commit_signal < 0)
    {
        CPU::ROB_new.h.clear();
        return;
    }

    if (CPU::commit_signal > 0)
        CPU::ROB_new.h.pop();

    if (!ROB_new.h.empty())
    {
        CPU::Reorder_Buffer::node &tmp = CPU::ROB_prev.h.get_front();
        CPU::Reorder_Buffer::node &p_prev = 
        (tmp.iscommit) ? CPU::ROB_prev.h.get_sec() : CPU::ROB_prev.h.get_front();
        CPU::Reorder_Buffer::node &p_new = CPU::ROB_new.h.get_front();

        if (p_prev.ready)
        {
            p_new.iscommit = 1;
            CPU::ROB_to_commit = p_new;
        }
    }

    const CPU::Reorder_Buffer::node &t = CPU::issue_to_ROB;
    if (~t.opcode)
        CPU::ROB_new.h.push(t);

    CPU::CDB c = CPU::ex_to_CDB;
    #ifdef func
        puts("ex_to_CDB");
        c.print();
    #endif 
    if (~c.dest)
    {
        CPU::ROB_new.h.node[c.dest].val = c.val;
        CPU::ROB_new.h.node[c.dest].pc = c.pos;
        CPU::ROB_new.h.node[c.dest].isjump = c.isjump;
        CPU::ROB_new.h.node[c.dest].ready = 1;
    }

    c = CPU::LSB_to_CDB_prev;
    #ifdef func
        puts("LSB_to_CDB");
        c.print();
    #endif 
    if (~c.dest)
    {
        CPU::ROB_new.h.node[c.dest].val = c.val;
        CPU::ROB_new.h.node[c.dest].ready = 1;
    }
        
    #ifdef func
        puts("issue_to_ROB");
        t.print();
    #endif 

    #ifdef func
        puts("-------------");
        puts("");
    #endif 
}

void CPU::ROB_commit()
{
    #ifdef func
        puts("");
        puts("---ROB_commit---");
    #endif 
    CPU::Reorder_Buffer::node &t = CPU::ROB_to_commit;

    #ifdef func
        puts("ROB_to_commit");
        t.print();
    #endif 

    if (!t.iscommit)
        return;

    #ifdef debug2
        printf("opcode:%d func3:%d func7:%d\n", t.opcode, t.func3, t.func7);
    #endif

    if (t.opcode == 55) // LUI
    {
        #ifdef debug2
            printf("lui %d %d\n", t.dest, t.val);
        #endif
        
    }
    else if (t.opcode == 23) // AUIPC
    {
        #ifdef debug2
            printf("auipc %d %d\n", t.dest, t.val);
        #endif
    }
    else if (t.opcode == 111) // JAL
    {
        #ifdef debug2
            printf("jal %d %d\n", t.dest, t.val);
        #endif
    }
    else if (t.opcode == 103) // JALR
    {
        #ifdef debug2
            printf("jalr %d %d\n", t.dest, t.val);
        #endif
    }
    else if (t.opcode == 99) // BEQ ~ BGEU
    {
        if (t.func3 == 0) // BEQ
        {
            #ifdef debug2
                printf("beq %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 1) // BNE
        {
            #ifdef debug2
                printf("bne %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 4) // BLT
        {
            #ifdef debug2
                printf("blt %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 5) // BEG
        {
            #ifdef debug2
                printf("beg %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 6) //BLTU
        {
            #ifdef debug2
                printf("bltu %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 7) // BGEU
        {
            #ifdef debug2
                printf("bgeu %d %d\n", t.dest, t.val);
            #endif
        }
    }
    else if (t.opcode == 3) // LB ~ LHU
    {
        #ifdef debug2
            printf("lb ~ lhu %d %d\n", t.dest, t.val);
        #endif
    }
    else if (t.opcode == 35) // SB ~ SW
    {
        #ifdef debug2
            printf("sb ~ sw %d %d\n", t.dest, t.val);
        #endif
    }
    else if (t.opcode == 19) // ADDI ~ SRAI
    {
        if (t.func3 == 0) // ADDI
        {
            #ifdef debug2
                printf("addi %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 2) // SLTI
        {
            #ifdef debug2
                printf("slti %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 3) // STLIU
        {
            #ifdef debug2
                printf("stliu %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 4) // XORI
        {
            #ifdef debug2
                printf("xori %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 6) // ORI
        {
            #ifdef debug2
                printf("ori %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 7) // ANDI
        {
            #ifdef debug2
                printf("andi %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 1) // SLLI
        {
            #ifdef debug2
                printf("slli %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 5) // SRLI ~ SRAI
        {
            if (t.func7 == 0) // SRLI
            {
                #ifdef debug2
                    printf("srli %d %d\n", t.dest, t.val);
                #endif
            }
            else if (t.func7 == 32) // SRAI
            {
                #ifdef debug2
                    printf("srai %d %d\n", t.dest, t.val);
                #endif
            }
        }
    }
    else if (t.opcode == 51) // ADD ~ AND
    {
        if (t.func3 == 0) // ADD ~ SUB
        {
            if (t.func7 == 0) // ADD
            {
                #ifdef debug2
                    printf("add %d %d\n", t.dest, t.val);
                #endif
            }
            else if (t.func7 == 32) // SUB
            {
                #ifdef debug2
                    printf("sub %d %d\n", t.dest, t.val);
                #endif
            }
        }
        else if (t.func3 == 1) // SLL
        {
            #ifdef debug2
                printf("sll %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 2) // SLT
        {
            #ifdef debug2
                printf("slt %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 3) // SLTU
        {
            #ifdef debug2
                printf("sltu %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 4) // XOR
        {
            #ifdef debug2
                printf("xor %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 5) // SRL ~ SRA
        {
            if (t.func7 == 0) // SRL
            {
                #ifdef debug2
                    printf("srl %d %d\n", t.dest, t.val);
                #endif
            }
            else if (t.func7 == 32) // SRA
            {
                #ifdef debug2
                    printf("sra %d %d\n", t.dest, t.val);
                #endif
            }
        }
        else if (t.func3 == 6) // OR
        {
            #ifdef debug2
                printf("or %d %d\n", t.dest, t.val);
            #endif
        }
        else if (t.func3 == 7) // AND
        {
            #ifdef debug2
                printf("and %d %d\n", t.dest, t.val);
            #endif
        }
    }

    CPU::commit_signal = 1;
    if (~t.dest)
        CPU::commit_to_reg = CPU::CDB(t.dest, t.val, t.pos);
    else if (t.val)
        CPU::commit_to_LSB = 1;

    if (t.isjump)
        CPU::commit_signal = -t.pc;

    t.iscommit = 0;
    #ifdef func
        puts("----------------");
        puts("");
    #endif 
}

#endif
#ifndef _Reservation_Station
#define _Reservation_Station
#include <iostream>
#include <cstring>
#include <cstdio>




bool CPU::RS_ready(const CPU::Reservation_Station::node &t)
{
    if (t.opcode == 55 || t.opcode == 23 || t.opcode == 111) // LUI AUIPC JAL 
        return 1;

    if (~t.Qj) return 0;

    if ((t.opcode == 99 || t.opcode == 51) && ~t.Qk) // BEQ ~ BGEU && ADD ~ AND
        return 0;

    return 1;
}

int CPU::RS_find()
{
    if (!CPU::RS_prev.h.empty())
    {
        for (int i = 0; i < CPU::queue_len; i++)
            if (CPU::RS_prev.h.busy[i] && CPU::RS_ready(CPU::RS_prev.h.node[i]))
                return i;
    }

    return -1;
}

void CPU::RS_run()
{
    #ifdef func
        puts("");
        puts("---RS_run---");
    #endif 
    CPU::RS_new = CPU::RS_prev;

    if (CPU::commit_signal < 0)
    {
        CPU::RS_new.h.clear();
        return;
    }

    CPU::Reservation_Station::node t = CPU::issue_to_RS;

    CPU::CDB c = CPU::ex_to_CDB;
    if (~c.dest)
    {
        for (int i = 0; i < CPU::queue_len; i++)
            if (CPU::RS_prev.h.busy[i])
            {
                if (CPU::RS_prev.h.node[i].Qj == c.dest)
                {
                    CPU::RS_new.h.node[i].Vj = c.val;
                    CPU::RS_new.h.node[i].Qj = -1;
                }

                if (CPU::RS_prev.h.node[i].Qk == c.dest)
                {
                    CPU::RS_new.h.node[i].Vk = c.val;
                    CPU::RS_new.h.node[i].Qk = -1;
                }
            }

        if (t.Qj == c.dest)
        {
            t.Vj = c.val;
            t.Qj = -1;
        }
        if (t.Qk == c.dest)
        {
            t.Vk = c.val;
            t.Qk = -1;
        }
    }

    c = CPU::LSB_to_CDB_prev;
    if (~c.dest)
    {
        for (int i = 0; i < CPU::queue_len; i++)
            if (CPU::RS_prev.h.busy[i])
            {
                if (CPU::RS_prev.h.node[i].Qj == c.dest)
                {
                    CPU::RS_new.h.node[i].Vj = c.val;
                    CPU::RS_new.h.node[i].Qj = -1;
                }

                if (CPU::RS_prev.h.node[i].Qk == c.dest)
                {
                    CPU::RS_new.h.node[i].Vk = c.val;
                    CPU::RS_new.h.node[i].Qk = -1;
                }
            }

        if (t.Qj == c.dest)
        {
            t.Vj = c.val;
            t.Qj = -1;
        }
        if (t.Qk == c.dest)
        {
            t.Vk = c.val;
            t.Qk = -1;
        }
    }

    if (~t.opcode)
        CPU::RS_new.h.push(t);

    #ifdef func
        puts("------------");
        puts("");
    #endif 

    int pos = CPU::RS_find();
    if (pos == -1) return;
    CPU::RS_to_ex = RS_new.h.node[pos];
    CPU::RS_new.h.pop(pos);
}

void CPU::RS_ex()
{
    #ifdef func
        puts("");
        puts("---RS_ex---");
    #endif 
    CPU::Reservation_Station::node &t = CPU::RS_to_ex;

    if (t.opcode == -1) return;

    if (t.opcode == 55) // LUI
    {
        #ifdef debug
            printf("lui %d %d\n", t.rd, t.imm);
        #endif

        CPU::ex_to_CDB = CPU::CDB(t.dest, t.A);
    }
    else if (t.opcode == 23) // AUIPC
    {
        #ifdef debug
            printf("auipc %d %d\n", t.rd, t.imm);
        #endif

        CPU::ex_to_CDB = CPU::CDB(t.dest, t.pc + t.A);
    }
    else if (t.opcode == 111) // JAL
    {
        #ifdef debug
            printf("jal %d %d\n", t.rd, t.imm);
        #endif

        CPU::ex_to_CDB = CPU::CDB(t.dest, t.pc + 4, t.pc + t.A, t.A != 4);
    }
    else if (t.opcode == 103) // JALR
    {
        #ifdef debug
            printf("jalr %d %d\n", t.rd, t.imm);
        #endif

        CPU::ex_to_CDB = CPU::CDB(t.dest, t.pc + 4, (t.Vj + t.A) & ~1, ((t.Vj + t.A) & ~1) - t.pc != 4);
    }
    else if (t.opcode == 99) // BEQ ~ BGEU
    {
        if (t.func3 == 0) // BEQ
        {
            #ifdef debug
                printf("beq %d %d\n", t.rd, t.imm);
            #endif

            if (t.Vj == t.Vk)
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0, t.pc + t.A, t.A != 4);
            }
            else
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0);
            }
        }
        else if (t.func3 == 1) // BNE
        {
            #ifdef debug
                printf("bne %d %d %d\n", t.rd, t.rs1_val, t.rs2_val);
            #endif

            if (t.Vj != t.Vk)
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0, t.pc + t.A, t.A != 4);
            }
            else
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0);
            }
        }
        else if (t.func3 == 4) // BLT
        {
            #ifdef debug
                printf("blt %d %d\n", t.rd, t.imm);
            #endif

            if (static_cast<int>(t.Vj) < static_cast<int>(t.Vk))
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0, t.pc + t.A, t.A != 4);
            }
            else
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0);
            }
        }
        else if (t.func3 == 5) // BEG
        {
            #ifdef debug
                printf("beg %d %d\n", t.rd, t.imm);
            #endif

            if (static_cast<int>(t.Vj) >= static_cast<int>(t.Vk))
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0, t.pc + t.A, t.A != 4);
            }
            else
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0);
            }
        }
        else if (t.func3 == 6) //BLTU
        {
            #ifdef debug
                printf("bltu %d %d\n", t.rd, t.imm);
            #endif

            if (t.Vj < t.Vk)
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0, t.pc + t.A, t.A != 4);
            }
            else
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0);
            }
        }
        else if (t.func3 == 7) // BGEU
        {
            #ifdef debug
                printf("bgeu %d %d %d\n", t.rd, t.rs1_val, t.rs2_val);
            #endif

            if (t.Vj >= t.Vk)
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0, t.pc + t.A, t.A != 4);
            }
            else
            {
                CPU::ex_to_CDB = CPU::CDB(t.dest, 0);
            }
        }
    }
    else if (t.opcode == 19) // ADDI ~ SRAI
    {
        if (t.func3 == 0) // ADDI
        {
            #ifdef debug
                printf("addi %d %d %d\n", t.rd, t.rs1_val, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj + t.A);
        }
        else if (t.func3 == 2) // SLTI
        {
            #ifdef debug
                printf("slti %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, static_cast<int>(t.Vj) < static_cast<int>(t.A));
        }
        else if (t.func3 == 3) // STLIU
        {
            #ifdef debug
                printf("stliu %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj < t.A);
        }
        else if (t.func3 == 4) // XORI
        {
            #ifdef debug
                printf("xori %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj ^ t.A);
        }
        else if (t.func3 == 6) // ORI
        {
            #ifdef debug
                printf("ori %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj | t.A);
        }
        else if (t.func3 == 7) // ANDI
        {
            #ifdef debug
                printf("andi %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj & t.A);
        }
        else if (t.func3 == 1) // SLLI
        {
            #ifdef debug
                printf("slli %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj << t.A);
        }
        else if (t.func3 == 5) // SRLI ~ SRAI
        {
            if (t.func7 == 0) // SRLI
            {
                #ifdef debug
                    printf("srli %d %d\n", t.rd, t.imm);
                #endif

                CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj >> t.A);
            }
            else if (t.func7 == 32) // SRAI
            {
                #ifdef debug
                    printf("srai %d %d\n", t.rd, t.imm);
                #endif

                CPU::ex_to_CDB = CPU::CDB(t.dest, sext(t.Vj >> t.A, 31 - t.A));
            }
        }
    }
    else if (t.opcode == 51) // ADD ~ AND
    {
        if (t.func3 == 0) // ADD ~ SUB
        {
            if (t.func7 == 0) // ADD
            {
                #ifdef debug
                    printf("add %d %d\n", t.rd, t.imm);
                #endif

                CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj + t.Vk);
            }
            else if (t.func7 == 32) // SUB
            {
                #ifdef debug
                    printf("sub %d %d\n", t.rd, t.imm);
                #endif

                CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj - t.Vk);
            }
        }
        else if (t.func3 == 1) // SLL
        {
            #ifdef debug
                printf("sll %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj << (t.Vk & ((1 << 5) - 1)));
        }
        else if (t.func3 == 2) // SLT
        {
            #ifdef debug
                printf("slt %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, static_cast<int>(t.Vj) < static_cast<int>(t.Vk));
        }
        else if (t.func3 == 3) // SLTU
        {
            #ifdef debug
                printf("sltu %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj < t.Vk);
        }
        else if (t.func3 == 4) // XOR
        {
            #ifdef debug
                printf("xor %d %d %d\n", t.rd, t.rs1_val, t.rs2_val);
            #endif

            // printf("XOR t.Vj:%u t.Vk:%u\n", t.Vj, t.Vk);

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj ^ t.Vk);
        }
        else if (t.func3 == 5) // SRL ~ SRA
        {
            if (t.func7 == 0) // SRL
            {
                #ifdef debug
                    printf("srl %d %d\n", t.rd, t.imm);
                #endif

                CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj >> (t.Vk & ((1 << 5) - 1)));
            }
            else if (t.func7 == 32) // SRA
            {
                #ifdef debug
                    printf("sra %d %d\n", t.rd, t.imm);
                #endif

                CPU::ex_to_CDB = CPU::CDB(t.dest, sext(t.Vj >> (t.Vk & ((1 << 5) - 1)), 31 - (t.Vk & ((1 << 5) - 1))));
            }
        }
        else if (t.func3 == 6) // OR
        {
            #ifdef debug
                printf("or %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj | t.Vk);
        }
        else if (t.func3 == 7) // AND
        {
            #ifdef debug
                printf("and %d %d\n", t.rd, t.imm);
            #endif

            CPU::ex_to_CDB = CPU::CDB(t.dest, t.Vj & t.Vk);
        }
    }

    t.opcode = -1;

    #ifdef func
        puts("-----------");
        puts("");
    #endif 
}

#endif
#ifndef _Registers
#define _Registers
#include <iostream>
#include <cstring>
#include <cstdio>




void CPU::reg_run()
{
    #ifdef func
        puts("");
        puts("---reg_run---");
    #endif 
    
    CPU::R_new = CPU::R_prev;

    const CPU::CDB &t = CPU::commit_to_reg;

    if (~t.dest)
    {
        CPU::R_new.reg[t.dest] = t.val;
        if (CPU::R_new.reg_state[t.dest] == t.pos)
            CPU::R_new.reg_state[t.dest] = -1;

        CPU::R_new.reg[0] = 0;
    }

    if (CPU::commit_signal < 0)
    {
        for (int i = 0; i < 32; i++)
            CPU::R_new.reg_state[i] = -1;
        return;
    }

    std::pair<int, int> p = CPU::issue_to_reg;
    if (~p.first)
        CPU::R_new.reg_state[p.first] = p.second;

    #ifdef func
        puts("-------------");
        puts("");
    #endif 
}

#endif
#ifndef _Load_Store_Buffer
#define _Load_Store_Buffer
#include <iostream>
#include <cstring>
#include <cstdio>




void CPU::LSB_run()
{
    #ifdef func
        puts("");
        puts("---LSB_run---");
    #endif 
    CPU::LSB_new = CPU::LSB_prev;

    CPU::Load_Store_Buffer::node t = CPU::issue_to_LSB;

    CPU::CDB c = CPU::ex_to_CDB;

    if (~c.dest)
    {
        for (int i = 0; i <= CPU::queue_len; i++)
            if (CPU::LSB_prev.h.busy[i])
            {
                if (CPU::LSB_prev.h.node[i].Qj == c.dest)
                {
                    CPU::LSB_new.h.node[i].Vj = c.val;
                    CPU::LSB_new.h.node[i].Qj = -1;
                }

                if (CPU::LSB_prev.h.node[i].Qk == c.dest)
                {
                    CPU::LSB_new.h.node[i].Vk = c.val;
                    CPU::LSB_new.h.node[i].Qk = -1;
                }
            }
        
        if (t.Qj == c.dest)
        {
            t.Vj = c.val;
            t.Qj = -1;
        }
        if (t.Qk == c.dest)
        {
            t.Vk = c.val;
            t.Qk = -1;
        }
    }

    c = CPU::LSB_to_CDB_prev;
    if (~c.dest)
    {
        for (int i = 0; i <= CPU::queue_len; i++)
            if (CPU::LSB_prev.h.busy[i])
            {
                if (CPU::LSB_prev.h.node[i].Qj == c.dest)
                {
                    CPU::LSB_new.h.node[i].Vj = c.val;
                    CPU::LSB_new.h.node[i].Qj = -1;
                }

                if (CPU::LSB_prev.h.node[i].Qk == c.dest)
                {
                    CPU::LSB_new.h.node[i].Vk = c.val;
                    CPU::LSB_new.h.node[i].Qk = -1;
                }
            }

        if (t.Qj == c.dest)
        {
            t.Vj = c.val;
            t.Qj = -1;
        }
        if (t.Qk == c.dest)
        {
            t.Vk = c.val;
            t.Qk = -1;
        }
    }

    if (~t.opcode)
        CPU::LSB_new.h.push(t);

    if (CPU::commit_to_LSB)
    {
        Cycle_Queue<CPU::Load_Store_Buffer::node, CPU::queue_len> h = CPU::LSB_prev.h;
        for (int i = h.get_next(h.front); i != h.get_next(h.rear); i = h.get_next(i))
        if (h.node[i].opcode == 35 && !h.node[i].iscommit)
        {
            CPU::LSB_new.h.node[i].iscommit = 1;
            break;
        }
    }

    if (CPU::commit_signal < 0)
    {
        while (!LSB_new.h.empty() && !LSB_new.h.get_rear().iscommit)
            LSB_new.h.pop_rear();
    }

    if (!LSB_prev.h.empty() && !LSB_new.h.empty())
    {
        const CPU::Load_Store_Buffer::node &p_prev = CPU::LSB_prev.h.get_front();
        CPU::Load_Store_Buffer::node &p_new = CPU::LSB_new.h.get_front();

        if (~p_prev.Qj) return;
        if (p_prev.opcode == 35 && ~p_prev.Qk) return;

        if (p_prev.tim == -1)
        {
            if (p_prev.opcode == 3)
                p_new.tim = 3;
            else
            {
                if (p_prev.iscommit)
                    p_new.tim = 3;
                else
                {
                    if (~p_prev.pos)
                        CPU::LSB_to_CDB_new = CPU::CDB(p_prev.dest, 1, -1);
                    p_new.pos = -1; // 表示已经发送过 CDB
                    p_new.tim = -1;
                }
            }
        }
        else
        {
            p_new.tim = p_prev.tim - 1;
            if (p_new.tim == 0)
            {
                CPU::LSB_new.h.pop();
                uint tmp = p_prev.Vj + p_prev.A;

                if (p_prev.opcode == 3) // LB ~ LHU
                {
                    if (p_prev.func3 == 0) // LB
                    {
                        CPU::LSB_to_CDB_new = CPU::CDB(p_prev.dest, sext(CPU::M.mem[tmp], 7));    
                    }
                    else if (p_prev.func3 == 1) // LH
                    {
                        CPU::LSB_to_CDB_new = CPU::CDB(p_prev.dest, sext(CPU::M.mem[tmp] + (CPU::M.mem[tmp + 1] << 8), 15));
                    }
                    else if (p_prev.func3 == 2) // LW
                    {
                        uint val = 0;
                        for (int i = 3; ~i; i--)
                            val = val << 8 | CPU::M.mem[tmp + i];
                        
                        CPU::LSB_to_CDB_new = CPU::CDB(p_prev.dest, val);
                    }
                    else if (p_prev.func3 == 4) // LBU
                    {
                        CPU::LSB_to_CDB_new = CPU::CDB(p_prev.dest, CPU::M.mem[tmp]);    
                    }
                    else if (p_prev.func3 == 5) // LHU
                    {
                        CPU::LSB_to_CDB_new = CPU::CDB(p_prev.dest, CPU::M.mem[tmp] + (CPU::M.mem[tmp + 1] << 8));
                    }
                }
                else if (p_prev.opcode == 35) // SB ~ SW
                {
                    if (p_prev.func3 == 0) // SB
                    {
                        CPU::M.mem[tmp] = p_prev.Vk & ((1 << 8) - 1);
                    }
                    else if (p_prev.func3 == 1) // SH
                    {
                        uint val = p_prev.Vk;
                        for (int i = 0; i < 2; i++)
                            CPU::M.mem[tmp + i] = val & ((1 << 8) - 1), val >>= 8;
                    }
                    else if (p_prev.func3 == 2) // SW
                    {
                        uint val = p_prev.Vk;
                        // printf("tmp:%d val:%u\n", tmp, val);
                        for (int i = 0; i < 4; i++)
                            CPU::M.mem[tmp + i] = val & ((1 << 8) - 1), val >>= 8;
                    }
                }
            }
        }
    }
    #ifdef func
        puts("-------------");
        puts("");
    #endif 
}

#endif
#endif
int main()
{
    CPU intelcorei9;
    intelcorei9.reader();
    intelcorei9.runner();
}